﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using umbraco.cms.businesslogic.web;
using System.Data.SqlClient;
using umbraco;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.datatype;
using umbraco.DataLayer;
using umbraco.interfaces;

namespace TheOutfield.UmbExt.UnVersion
{
    public class ApplicationBase : umbraco.BusinessLogic.ApplicationBase
    {
        public ApplicationBase()
        {
            Document.AfterPublish += new Document.PublishEventHandler(Document_UnVersion);
        }

        protected void Document_UnVersion(Document doc, object e)
        {
            if (HttpContext.Current == null)
                return;

            var configEntries = new List<UnVersionConfigEntry>();

            if (UnVersionConfig.Instance.ConfigEntries.ContainsKey(doc.ContentType.Alias))
                configEntries.AddRange(UnVersionConfig.Instance.ConfigEntries[doc.ContentType.Alias]);

            if (UnVersionConfig.Instance.ConfigEntries.ContainsKey("$_ALL"))
                configEntries.AddRange(UnVersionConfig.Instance.ConfigEntries["$_ALL"]);

            if (configEntries.Count > 0)
            {
                foreach (var configEntry in configEntries)
                {
                    var isValid = true;
                    if (!String.IsNullOrEmpty(configEntry.RootXPath))
                    {
                        if (doc.Level > 1 && doc.Parent != null)
                        {
                            var ids = GetNodeIdsFromXpath(configEntry.RootXPath);
                            isValid = ids.Contains(doc.Parent.Id);
                        }
                    }

                    if (!isValid)
                        continue;

                    // UnVersion
                    try
                    {
                        // Get a list of all versions
                        // TODO: Need to find a better way to do this, but SQL CE 4 doesn't allow sub queries
                        var reader = Application.SqlHelper.ExecuteReader(string.Format(
                                @"SELECT			cv.VersionId,
	                                                cv.VersionDate,
	                                                d.published,
	                                                d.newest
                                FROM				cmsContentVersion cv
                                LEFT OUTER JOIN		cmsDocument d ON d.versionId = cv.VersionId
                                WHERE				cv.ContentId = {0}
                                ORDER BY            cv.VersionDate DESC",
                                doc.Id));

                        var readerIndex = 0;
                        var versionsToKeep = new List<string>();

                        if (reader != null)
                        {
                            while (reader.Read())
                            {
                                var versionId = reader.GetGuid("VersionId");
                                var versionDate = reader.GetDateTime("VersionDate");
                                var published = reader.GetBoolean("published");
                                var newest = reader.GetBoolean("newest");

                                readerIndex++;

                                if(published || newest || readerIndex <= configEntry.MaxCount || (DateTime.Now - versionDate).Days < configEntry.MaxDays)
                                    versionsToKeep.Add("'"+ versionId.ToString("D") +"'");
                            }

                            reader.Close();
                        }

                        var versionsToKeepString = string.Join(",", versionsToKeep.ToArray());

                        // Get version number
                        var versionNo = Convert.ToInt32(Regex.Replace(GlobalSettings.CurrentVersion, "[^0-9]", "").PadRight(5, '0'));
                        
                        // Delete version info
                        // TODO: Need to find a better way to do this, SQL CE 4 doesn't allow multiple queries at once
                        if (versionNo >= 45000)
                        {
                            Application.SqlHelper.ExecuteNonQuery(string.Format(@"
                                DELETE
                                FROM	cmsPreviewXml
                                WHERE	nodeId = {0} AND versionId NOT IN ({1})",
                                doc.Id,
                                versionsToKeepString));
                        }

                        Application.SqlHelper.ExecuteNonQuery(string.Format(@"
                                DELETE
                                FROM	cmsPropertyData
                                WHERE	contentNodeId = {0} AND versionId  NOT IN ({1})",
                                doc.Id,
                                versionsToKeepString));

                        Application.SqlHelper.ExecuteNonQuery(string.Format(@"
                                DELETE
                                FROM	cmsContentVersion
                                WHERE	contentId = {0} AND versionId  NOT IN ({1})",
                                doc.Id,
                                versionsToKeepString));

                        Application.SqlHelper.ExecuteNonQuery(string.Format(@"
                                DELETE
                                FROM	cmsDocument 
                                WHERE	nodeId = {0} AND versionId  NOT IN ({1})",
                                doc.Id,
                                versionsToKeepString));

                        

                    }
                    catch
                    { }
                }

            }
        }

        protected List<int> GetNodeIdsFromXpath(string xpath)
        {
            var ids = new List<int>();
            var nodes = umbraco.library.GetXmlNodeByXPath(xpath);
            while (nodes.MoveNext())
            {
                ids.Add(Convert.ToInt32(nodes.Current.GetAttribute("id", "")));
            }
            return ids;
        }
    }
}